import React, { useState, useEffect, useRef, ReactNode, useMemo } from 'react';
import { Column, Table, TableHeaderProps } from "react-virtualized";
import { Resizable } from 'react-resizable';
import { useDrop, useDrag } from 'react-dnd';
import { Button, Tooltip, Dropdown, Space } from 'antd'
import { HolderOutlined, PlusOutlined } from '@ant-design/icons';
import { useDispatch, useSelector } from 'react-redux';
import { State } from '@/apps/panel/reducers';
import { indentCreatedByCommand } from '@/common/command'
import { repeatStr } from '@/common/ts_utils';
import { commandText } from '@/common/command';
import classNames from 'classnames';
import * as act from '@/apps/panel/actions'
import { PLAY_MODE } from '@/types/player'
import { eventBus } from '@/common/eventBus';
import { waitForRenderComplete } from '@/common/utils'
import './index.less'

const RcvTable: any = Table
const ColumnComponent: any = Column
const ITEM_HEIGHT = 40;
const ResizableComponet: any = Resizable;
type ColumnKey = 'holderFixed' | 'serialFixed' | 'cmd' | 'target' | 'value' | 'opsFixed';

interface HandleProps {
    handleAxis: string;
    [key: string]: any;
}

// 行组件
const RowItem = ({ rowData, attributes, style, className, editable, columnWidths, tableWidth, index, moveItem }: { rowData: any, attributes: any; style: any, className: string; editable: boolean; columnWidths: any, tableWidth: any, index: number }) => {

    const ref = useRef<HTMLSpanElement | null>(null);
    const dispatch = useDispatch()

    const [lastOperation, setLastOperation] = useState('')
    const [{ isDragging }, drag, preview] = useDrag({
        type: 'ROW',
        item: { originalIndex: index },
        collect: (monitor) => {
            return {
                isDragging: monitor.isDragging(),
            }
        },
        end: (item: { originalIndex: number }, monitor) => {
            const didDrop = monitor.didDrop()
            if (!didDrop) {
                // 非法移动，还原到原始位置
                moveItem(item.originalIndex, index)
            }
        },
        isDragging: (monitor) => {
            return monitor.getItem()?.originalIndex === index
        }
    });

    const [_, drop] = useDrop({
        accept: ['ROW'],
        hover: (item: { originalIndex: number }, monitor) => {

            const dragIndex: number = item.originalIndex
            const hoverIndex: number = index

            if (dragIndex === hoverIndex) {
                return
            }

            const clientOffset = monitor.getClientOffset();
            const el: any = ref.current;
            if (!el || !clientOffset) return;

            const hoverBoundingRect = el.getBoundingClientRect();
            const halfHeight = hoverBoundingRect.height / 2
            const yInElement = clientOffset.y - hoverBoundingRect.top

            if (dragIndex < hoverIndex && yInElement < halfHeight) {
                return
            }

            // Dragging upwards
            if (dragIndex > hoverIndex && yInElement > halfHeight) {
                return
            }

            moveItem(dragIndex, hoverIndex)
            item.originalIndex = hoverIndex;

        },
    });

    const playCommandInterval = useSelector((state: State) => state.config.playCommandInterval)
    const macroId = useSelector((state: State) => state.editor.editing.meta.src?.id) || '__untitled__'
    const macroName = useSelector((state: State) => state.editor.editing.meta.src?.name) || 'Untitled'
    const commands = useSelector((state: State) => state.editor.editing.commands)
    const breakpointIndices = useSelector((state: State) => {
        const macroId = state.editor.editing.meta.src?.id || '__untitled__'
        const extra: any = state.editor.macrosExtra[macroId]
        return extra?.breakpointIndices
    }) || []
    const isBreakpoint = breakpointIndices.indexOf(index) !== -1

    return (
        <Dropdown
            menu={{
                items: [
                    {
                        key: 'cut',
                        label: '剪切 Ctrl+X',
                    },
                    {
                        key: 'copy',
                        label: '复制 Ctrl+C',
                    },
                    {
                        key: 'paste',
                        label: '粘贴 Ctrl+C',
                    },
                    {
                        key: 'delete',
                        label: '删除 Delete',
                    },
                    {
                        type: 'divider',
                    },
                    {
                        key: 'insert',
                        label: '插入新行'
                    },
                    {
                        key: 'jumpToSourceCode',
                        label: '跳转到源码'
                    },
                    {
                        key: isBreakpoint ? 'removeBreakpoint' : 'addBreakpoint',
                        label: isBreakpoint ? '移除断点' : '添加断点'
                    },
                    {
                        type: 'divider',
                    },
                    {
                        key: 'runLine',
                        label: '执行此步'
                    },
                    {
                        key: 'playFromHere',
                        label: '从此步执行'
                    },
                    {
                        key: 'playFromHereKeepVariables',
                        label: '保持运行变量从此步执行'
                    },
                    {
                        key: 'playToHere',
                        label: '运行到此步'
                    },
                    {
                        key: 'recordFromHere',
                        label: '从此步录制'
                    },
                    // {
                    //     key: 'jumpToImage',
                    //     label: '跳转到图片'
                    // }
                ],
                onClick: (e) => {
                    switch (e.key) {
                        case 'cut': {
                            dispatch(act.cutCommand(index))
                            break
                        }
                        case 'copy': {
                            dispatch(act.copyCommand(index))
                            break
                        }
                        case 'paste': {
                            dispatch(act.pasteCommand(index))
                            break
                        }
                        case 'insert': {
                            dispatch(act.insertCommand({
                                cmd: '',
                                target: '',
                                value: ''
                            }, index + 1))
                            break
                        }
                        case 'delete': {
                            dispatch(act.removeCommand(index))
                            break
                        }
                        case 'runLine': {
                            setLastOperation('play')
                            dispatch(act.playerPlay({
                                macroId,
                                title: macroName,
                                extra: {
                                    id: macroId
                                },
                                mode: PLAY_MODE.SINGLE, // 执行单行
                                startIndex: index,
                                startUrl: null,
                                resources: commands,
                                postDelay: playCommandInterval * 1000,
                            }))
                            break
                        }
                        case 'playFromHere': {
                            setLastOperation('play')
                            dispatch(act.playerPlay({
                                macroId,
                                title: macroName,
                                extra: { id: macroId },
                                mode: PLAY_MODE.STRAIGHT,
                                startIndex: index,
                                keepVariables: 'reset',
                                startUrl: null,
                                resources: commands,
                                postDelay: playCommandInterval * 1000
                            }))
                            break
                        }
                        case 'playFromHereKeepVariables': {
                            setLastOperation('play')
                            dispatch(act.playerPlay({
                                macroId,
                                title: macroName,
                                extra: { id: macroId },
                                mode: PLAY_MODE.STRAIGHT,
                                startIndex: index,
                                keepVariables: 'yes',
                                startUrl: null,
                                resources: commands,
                                postDelay: playCommandInterval * 1000
                            }))
                            break
                        }
                        case 'playToHere': {
                            setLastOperation('play')
                            dispatch(act.playerPlay({
                                macroId,
                                title: macroName,
                                extra: { id: macroId },
                                mode: PLAY_MODE.STRAIGHT,
                                keepVariables: 'reset',
                                startIndex: 0,
                                startUrl: null,
                                resources: commands,
                                postDelay: playCommandInterval * 1000,
                                breakpoints: [index]
                            }))
                            break
                        }
                        case 'addBreakpoint': {
                            dispatch(act.addBreakpoint(macroId, index) as any)
                            break
                        }
                        case 'removeBreakpoint': {
                            dispatch(act.removeBreakpoint(macroId, index) as any)
                            break
                        }
                        case 'jumpToSourceCode': {
                            eventBus.emit('jumpToSourceCode', index); // 🔔 触发事件
                            break
                        }
                        case 'jumpToImage': {
                            eventBus.emit('jumpToImage', index); // 🔔 触发事件
                            break
                        }
                        case 'recordFromHere': {
                            dispatch(act.setIndexToInsertRecorded(index + 1))
                            dispatch(act.toggleRecorderSkipOpen(true))
                            dispatch(act.startRecording())
                            break
                        }
                        default: {

                        }
                    }
                }
            }}
            trigger={['contextMenu']}
        >
            <div
                ref={(node) => {
                    preview(node);
                    drop(node);
                }}
                {...attributes || {}}
                style={{ ...style, width: tableWidth }}
                className={classNames(className, { dragging: isDragging })}
                onClick={() => {
                    dispatch(act.updateUI({ focusArea: 'command_table' }))
                    dispatch(act.selectCommand(index, true))
                }}
            >
                <div
                    ref={(node) => {
                        ref.current = node;
                        drag(drop(ref));
                    }}
                    className="row-col holder-col"
                    style={{
                        width: columnWidths.holderFixed,
                        cursor: 'move',
                        marginRight: '5px'
                    }}>
                    <HolderOutlined />
                </div>
                <div className="row-col index-col" style={{ width: columnWidths.serialFixed }}>
                    {index}
                </div>
                <div
                    className="row-col cmd-col"
                    style={{ width: columnWidths.cmd * (tableWidth - columnWidths.holderFixed - columnWidths.serialFixed - columnWidths.opsFixed) }}
                    title={commandText(rowData.cmd)}
                >
                    {repeatStr(rowData.indent * 4, '\u00A0')}{commandText(rowData.cmd)}
                </div>
                <div className="row-col target-col" style={{ width: columnWidths.target * (tableWidth - columnWidths.holderFixed - columnWidths.serialFixed - columnWidths.opsFixed) }}>{rowData.target}</div>
                <div className="row-col value-col" style={{ width: columnWidths.value * (tableWidth - columnWidths.holderFixed - columnWidths.serialFixed - columnWidths.opsFixed) }}>{rowData.value}</div>
                <div className="row-col ops-col" style={{ minWidth: columnWidths.opsFixed }}>
                    <Space size={4}>
                        {rowData.description ? (
                            <Tooltip title={rowData.description}>
                                <Button
                                    disabled={!editable}
                                    type="primary"
                                    shape="circle"
                                    size="small"
                                    className='commentout-button'
                                    onClick={(e) => {
                                        dispatch(act.toggleComment(index) as any)
                                        e.stopPropagation()
                                    }}
                                    icon={<div>//</div>}
                                >
                                </Button>
                            </Tooltip>
                        ) : (
                            <Button
                                disabled={!editable}
                                shape="circle"
                                size="small"
                                className='commentout-button'
                                onClick={(e) => {
                                    dispatch(act.toggleComment(index) as any)
                                    e.stopPropagation()
                                }}
                                icon={<div>//</div>}
                            >
                            </Button>
                        )}
                        <Button
                            disabled={!editable}
                            shape="circle"
                            size="small"
                            onClick={(e) => {
                                dispatch(act.duplicateCommand(index))
                                e.stopPropagation()
                            }}
                        >
                            <PlusOutlined />
                        </Button>
                    </Space>
                </div>
            </div>
        </Dropdown>
    )
}

// 拖拽手柄
const ResizableHandle = React.forwardRef<HTMLDivElement, HandleProps>((props, ref) => {
    const { handleAxis, ...restProps } = props;
    return <div ref={ref} className={`column-resizable-handle handle-${handleAxis}`} {...restProps} >⋮</div>;
});

// 表格组件
export default function ResizableTable() {

    const tableContainerRef = useRef<HTMLDivElement>(null);
    const dispatch = useDispatch()

    const [columnWidths, setColumnWidths] = useState<Record<ColumnKey, number>>({
        holderFixed: 30,
        serialFixed: 30,
        cmd: .3,
        target: .4,
        value: .3,
        opsFixed: 100
    });

    const [tableWidth, setTableWidth] = useState(0);
    const [tableHeight, setTableHeight] = useState(0);

    const commands = useSelector((state: State) => state.editor.editing.commands);
    const focusArea = useSelector((state: State) => state.ui.focusArea)
    const selectedIndex = useSelector((state: State) => state.editor.editing.meta.selectedIndex)
    const nextCommandIndex = useSelector((state: State) => state.player.nextCommandIndex)
    const breakpointIndices = useSelector((state: State) => (state.editor.macrosExtra[state.editor.editing.meta.src?.id || ''] as any)?.breakpointIndices) || []
    const doneCommandIndices = useSelector((state: State) => (state.editor.macrosExtra[state.editor.editing.meta.src?.id || ''] as any)?.doneCommandIndices) || []
    const errorCommandIndices = useSelector((state: State) => (state.editor.macrosExtra[state.editor.editing.meta.src?.id || ''] as any)?.errorCommandIndices) || []
    const warningCommandIndices = useSelector((state: State) => (state.editor.macrosExtra[state.editor.editing.meta.src?.id || ''] as any)?.warningCommandIndices) || []

    const dataSource = useMemo(() => {
        const { dataSource } = commands.reduce(({ dataSource, indent }: any, command: any, i: number) => {
            const { selfIndent, nextIndent } = indentCreatedByCommand(command.cmd)

            dataSource.push({
                ...command,
                indent: indent + selfIndent,
                serial: i + 1
            })

            return {
                dataSource,
                indent: Math.max(0, indent + selfIndent + nextIndent)
            }
        }, { dataSource: [], indent: 0 })
        return dataSource;
    }, [commands]) // 增加id

    // 调整列宽
    const resizeColumnWidth = ({ dataKey, deltaX }: { dataKey: string; deltaX: number }) => {
        setColumnWidths((prevWidths) => {
            const percentDelta = deltaX / (tableWidth - prevWidths.holderFixed - prevWidths.serialFixed - prevWidths.opsFixed)
            let nextDataKey: ColumnKey

            switch (dataKey) {
                case 'cmd':
                    nextDataKey = 'target'
                    break
                case 'target':
                    nextDataKey = 'value'
                    break
                case 'value':
                    nextDataKey = 'opsFixed'
                    break
                default:
                    nextDataKey = 'target';
            }

            return {
                ...prevWidths,
                [dataKey as ColumnKey]: prevWidths[dataKey as ColumnKey] + percentDelta,
                [nextDataKey]: prevWidths[nextDataKey] - percentDelta
            }
        })
    };

    // 表头渲染
    const headerRenderer = (props: TableHeaderProps) => {
        const width = columnWidths[props.dataKey as ColumnKey] * tableWidth
        return (
            <ResizableComponet
                key={props.dataKey}
                width={width}
                handle={<ResizableHandle />}
                onResize={(e: any, { size }: any) => {
                    resizeColumnWidth({
                        dataKey: props.dataKey as ColumnKey,
                        deltaX: size.width - width
                    })
                }}
                draggableOpts={{ enableUserSelectHack: false }}
                axis='x'
            >
                <div className="ReactVirtualized__Table__headerTruncatedText">
                    {props.label as ReactNode}
                </div>
            </ResizableComponet>
        );
    };


    const canUseKeyboardShortcuts = focusArea === 'command_table'

    const commandClassName = (record: any, index: number) => {

        const classNames = []
        if (breakpointIndices.indexOf(index) !== -1) {
            classNames.push('breakpoint-command')
        }
        if (record.cmd === 'comment' || record.cmd === '') {
            classNames.push('comment-command')
        }
        if (!canUseKeyboardShortcuts) {
            classNames.push('blur')
        }
        if (index === nextCommandIndex) {
            classNames.push('running-command')
        } else if (warningCommandIndices.indexOf(index) !== -1) {
            classNames.push('warning-command')
        } else if (errorCommandIndices.indexOf(index) !== -1) {
            classNames.push('error-command')
        } else if (doneCommandIndices.indexOf(index) !== -1) {
            classNames.push('done-command')
        }
        if (index === selectedIndex) {
            classNames.push('selected-command')
        }
        return classNames.join(' ')
    }


    const moveItem = (dragIndex: number, hoverIndex: number) => {
        dispatch(act.moveCommands(dragIndex, hoverIndex))
    }


    useEffect(() => {

        // 创建ResizeObserver实例
        const resizeObserver = new ResizeObserver(entries => {
            for (const entry of entries) {
                const { width, height } = entry.contentRect;
                setTableWidth(width)
                setTableHeight(height)
                console.log(`新宽度: ${width}px, 新高度: ${height}px ${entry.contentRect}`);
                // 在此处执行尺寸变化后的逻辑（如重绘图表、调整布局）
            }
        });

        // 监听目标
        resizeObserver.observe(tableContainerRef.current!);

        return () => {
            // 取消监听
            resizeObserver.unobserve(tableContainerRef.current!)
        }

    }, [])

    useEffect(() => {
        waitForRenderComplete('.command-table-wrapper').then(() => {
            if (tableContainerRef.current) {
                setTableWidth(tableContainerRef.current.clientWidth)
                setTableHeight(tableContainerRef.current.clientHeight)
            }
        })
    }, [])

    useEffect(() => {
        const onWindowResize = () => {
            if (tableContainerRef.current) {
                setTableWidth(tableContainerRef.current.clientWidth)
                setTableHeight(tableContainerRef.current.clientHeight)
            }
        }
        window.addEventListener('resize', onWindowResize)
        return () => {
            window.removeEventListener('resize', onWindowResize)
        }
    }, [])

    return (
        <div className="table-view" >
            <div className="command-table-wrapper" ref={tableContainerRef}>
                <RcvTable
                    className='command-table'
                    width={tableWidth}
                    height={tableHeight}
                    headerHeight={ITEM_HEIGHT}
                    rowHeight={ITEM_HEIGHT}
                    rowCount={dataSource.length + 1}
                    rowClassName={() => 'command-row-header'}
                    rowGetter={({ index }: any) => dataSource[index] || { id: index }}
                    rowRenderer={({ rowData, key, index, style }: any) => {

                        if (index === dataSource.length) {
                            return (
                                <div
                                    key="footer"
                                    className="command-row footer-row"
                                    style={{
                                        top: index * ITEM_HEIGHT
                                    }}
                                    onClick={() => {
                                        dispatch(act.updateUI({ focusArea: 'command_table' }))
                                        dispatch(act.insertCommand({
                                            cmd: '',
                                            target: '',
                                            value: ''
                                        }, commands.length))
                                    }}
                                >
                                    新增
                                </div>
                            )
                        }

                        return (
                            <RowItem
                                editable={true}
                                index={index}
                                rowData={rowData}
                                key={key}
                                style={{ ...style, height: ITEM_HEIGHT + 'px', }}
                                columnWidths={columnWidths}
                                tableWidth={tableWidth}
                                attributes={{ 'data-index': '' + index }}
                                className={`command-row real-command ` + commandClassName(rowData, index)}
                                moveItem={moveItem}
                            />
                        );
                    }}
                >
                    <ColumnComponent
                        label=""
                        dataKey="holder"
                        width={columnWidths.holderFixed}
                    />
                    <ColumnComponent
                        label=""
                        dataKey="serial"
                        width={columnWidths.serialFixed}
                    />
                    <ColumnComponent
                        headerRenderer={headerRenderer}
                        label="命令"
                        dataKey="cmd"
                        width={columnWidths.cmd * (tableWidth - columnWidths.holderFixed - columnWidths.serialFixed - columnWidths.opsFixed)}
                    />
                    <ColumnComponent
                        headerRenderer={headerRenderer}
                        label="目标"
                        dataKey="target"
                        width={columnWidths.target * (tableWidth - columnWidths.holderFixed - columnWidths.serialFixed - columnWidths.opsFixed)}
                    />
                    <ColumnComponent
                        label="值"
                        dataKey="value"
                        width={columnWidths.value * (tableWidth - columnWidths.holderFixed - columnWidths.serialFixed - columnWidths.opsFixed)}
                    />
                    <ColumnComponent
                        dataKey="ops"
                        label="操作"
                        width={columnWidths.opsFixed}
                    />
                </RcvTable>
            </div>
            {/* <RightSidebar /> */}
        </div>
    );
};